import scala.collection.mutable.ListBuffer
import scala.io.{BufferedSource, Source}

object Demo11List {
  def main(args: Array[String]): Unit = {
    /**
     * List 列表
     * 特点：不可变、有序的、元素可以重复
     * 常见的操作：map、foreach、filter、flatMap、sortBy、groupBy
     */
    // 创建一个元素都为Int类型的List 默认属于immutable包下 是不可变的
    val list1: List[Int] = List[Int](1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 5, 6, 7)

    // 可以通过下标取元素 --> 有序的
    println(list1(3))

    // 打印List 可以看到List中所有的元素
    println(list1)

    // List常见的用法
    println(list1.size) // 获取大小
    println(list1.length) // 获取大小
    println(list1.head) // 获取第一个元素
    println(list1.last) // 获取最后一个元素
    println(list1.tail) // 获取除第一个元素以外的所有的元素
    println(list1.take(4)) // 获取指定数量的前n个元素
    println(list1.sum) // 求所有元素的加和
    println(list1.max) // 获取最大值
    println(list1.min) // 获取最小值
    println(list1.distinct) // 获取去重后的结果
    println(list1.isEmpty) // 判断List是否为空
    println(list1.reverse) // 将List反转 得到一个新的List

    // 所有的操作并不会对原有的List造成影响
    println(list1)

    // List常见的高级操作
    val list2: List[Int] = List[Int](1, 2, 3, 4, 5, 6)

    /**
     * foreach 和 map 方法的对比：
     * 都需要接收一个函数f
     * 函数f的 参数类型都为Int，因为List中的每个元素都为Int类型
     * 函数f的 返回值类型不同 foreach要求返回值类型为Unit，map的返回值任意
     */
    // 遍历
    list2.foreach(println)
    // 将每个元素 做一个 次方
    println(list2.map(i => i * i * i))

    // 过滤出list2中的奇数

    /**
     * filter方法 对元素进行过滤
     * 需要接受一个函数p: Int => Boolean
     * 根据最后的返回结果进行过滤
     * 如果返回的是true --> 保留
     * 如果返回的是false --> 过滤
     *
     */

    def filterOdd(i: Int): Boolean = {
      var flag: Boolean = false
      if (i % 2 == 1) {
        flag = true
      }
      flag
    }

    println(list2.filter(filterOdd))

    // 用匿名函数简化
    println(list2.filter((i: Int) => {
      var flag: Boolean = false
      if (i % 2 == 1) {
        flag = true
      }
      flag
    }))

    println(list2.filter((i: Int) => {
      i % 2 == 1
    }))

    println(list2.filter(i => i % 2 == 1)) // 过滤奇数
    println(list2.filter(i => i % 2 == 0)) // 过滤偶数


    val bs: BufferedSource = Source
      .fromFile("Scala/data/students.txt")

    val listStu: List[String] = bs.getLines()
      .toList
    // 默认每个元素都是String类型 不方便提取 name、age等属性
    listStu.foreach(println)

    // 将每条学生数据变成StuL的对象
    val stuList: List[StuL] = listStu
      // line 相当每一条数据
      .map(line => {
        val split: Array[String] = line.split(",")
        StuL(split(0), split(1), split(2), split(3), split(4))
      })

    // 过滤文科一班
    println(stuList.filter(s => "文科一班".equals(s.clazz)))


    // 关闭文件
    bs.close()

    // 统计班级人数

    /**
     * groupBy方法需要接收一个函数f: StuL => K
     * K 表示从 StuL的对象中 提取某个元素 或者叫做 指定一个分组字段
     * 会返回一个Map
     */

    def groupFunc(stu: StuL): String = {
      stu.clazz
    }

    stuList
      .groupBy(groupFunc)

    // 使用匿名函数简化
    stuList
      .groupBy(stu => stu.clazz)
      .map(kv => {
        s"${kv._1},${kv._2.size}"
      })
      .foreach(println)
    /**
     * flatMap 类似map方法
     * 需要一个函数f: String => GenTraversableOnce
     * 返回值类型GenTraversableOnce表示：可以遍历的数据容器 例如：List、Array
     * 最终flatMap会将返回的可以遍历的数据容器进行扁平化处理（展开）
     */
    val strList: List[String] = List[String]("java,scala,python", "hadoop,hive,hbase", "spark,flink,mapReduce")

    strList.flatMap((str: String) => {
      str.split(",")
    }).foreach(println)

    /**
     * 排序的操作 sorted、sortBy、sortWith
     */

    val list3: List[Int] = List[Int](1, 2, 5, 4, 6, 3, 7, 9, 8)

    println(list3.sorted) // 默认按照升序排列

    // sortBy 指定一个排序的字段
    stuList.sortBy(stu => stu.age).foreach(println)

    // sortWith 指定一个排序规则
    println(list3.sortWith((i1, i2) => i1 > i2))

    println("#" * 30)

    // 可变List --> ListBuffer
    val lb1: ListBuffer[Int] = ListBuffer[Int](1, 2, 2, 3, 3, 4, 2, 6, 5, 7, 8, 9)

    println(lb1)

    // 增加
    lb1.append(10)
    lb1.+=(11)

    //    val str: String = lb1.+("abc")
    //    println(str)
    lb1.insert(3, 100)
    println(lb1)
    // 修改
    lb1(3) = 101
    lb1.update(4, 300)

    println(lb1)

    // 删除
    lb1.remove(3) // 指定索引位置进行删除
    lb1 -= 300
    println(lb1)
    // 其他操作同List一样

  }

}

case class StuL(id: String, name: String, age: String, gender: String, clazz: String)